//重新实现function的bind方法
Function.prototype.bind = function (context) {
    var self = this
    return function () {
        return self.apply(context, arguments)
    }
}
//重新实现function的call方法
Function.prototype.call = function (context) {
    context.fn = this
    var args = []
    for (var i = 1; i < arguments.length; i++) {
        args.push(arguments[i])
    }
    var result = context.fn(...args)
    delete context.fn
    return result
}
Function.call(context,arg1,arg2,arg3)
//重新实现function的apply方法
Function.prototype.apply = function (context, arr) {
    context.fn = this
    var result
    if (!arr) {
        result = context.fn()
    } else {
        var args = []
        for (var i = 0; i < arr.length; i++) {
            args.push(arr[i])
        }
        result = context.fn(...args)
    }
    delete context.fn
    return result
}
/**
 * function的call方法和apply方法的区别在于传参的方式不同，call方法传参是一个一个传，apply方法传参是一个数组
 * function的bind方法的原理是返回一个新的函数，这个函数的this指向传入的参数，这个函数的参数是传入的参数
 * 举个例子来解释function的bind方法的原理
 */
var obj = {
    name: 'obj'
}
function testBind() {
    //为何可以使用this.name，因为this指向的是obj
    console.log(this.name)
}
var testBindObj = testBind.bind(obj)
testBindObj() //obj
/**
 * callee属性是arguments对象的一个属性，它可以用于引用该函数的函数体内当前正在执行的函数
 * 
 * 为什么function中可直接使用arguments，因为arguments是函数的一个属性，它是一个类数组对象，它有一个callee属性，指向拥有这个arguments对象的函数
 */

